package com.sky.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.sky.constant.MessageConstant;
import com.sky.context.BaseContext;
import com.sky.dto.*;
import com.sky.entity.AddressBook;
import com.sky.entity.OrderDetail;
import com.sky.entity.Orders;
import com.sky.entity.ShoppingCart;
import com.sky.exception.OrderBusinessException;
import com.sky.mapper.*;
import com.sky.result.PageResult;
import com.sky.service.OrderService;
import com.sky.vo.*;
import com.sky.websocket.WebSocketServer;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.ss.usermodel.*;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;


/**
 * OrderServiceImpl
 *
 * @author liliudong
 * @version 1.0
 * @description OrderService
 * @date 2023/8/4 9:42
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class OrderServiceImpl implements OrderService {

    private final ShoppingCartMapper shoppingCartMapper;

    private final OrdersMapper ordersMapper;

    private final AddressBookMapper addressBookMapper;

    private final OrderDetailMapper orderDetailMapper;

    private final WebSocketServer webSocketServer;

    private final UserMapper userMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public OrderSubmitVO submit(OrdersSubmitDTO ordersSubmitDTO) {
        // 谁要买什么东西进行下单
        // 1. 查询这个人的购物车所有商品
        ShoppingCart shoppingCart = new ShoppingCart();
        shoppingCart.setUserId(BaseContext.getCurrentId());
        List<ShoppingCart> shoppingCartList = shoppingCartMapper.selectList(shoppingCart);
        if (CollectionUtils.isEmpty(shoppingCartList)) {
            throw new OrderBusinessException(MessageConstant.SHOPPING_CART_IS_NULL);
        }
        // 2. 创建订单，并且初始化订单数据（算总价、保存基本信息（什么人、什么地址、什么时间））
        Orders orders = new Orders();
        // 业务上的订单号 - 年月日、随机码、用户标识
        // 时间戳
        long currentTimeMillis = System.currentTimeMillis();
        orders.setNumber(String.valueOf(currentTimeMillis));
        orders.setStatus(Orders.PENDING_PAYMENT);
        orders.setUserId(BaseContext.getCurrentId());
        orders.setAddressBookId(ordersSubmitDTO.getAddressBookId());
        orders.setOrderTime(LocalDateTime.now());
        orders.setPayMethod(1);
        orders.setPayStatus(Orders.UN_PAID);
        // 总金额 = 商品总金额之和 + 打包费
        int packAmount = ordersSubmitDTO.getPackAmount() == null ? 0 : ordersSubmitDTO.getPackAmount();
        BigDecimal amount = shoppingCartList.stream()
                .map(ShoppingCart::getAmount)
                .reduce(new BigDecimal(packAmount), BigDecimal::add);
        orders.setAmount(amount);
        orders.setRemark(ordersSubmitDTO.getRemark());

        orders.setDeliveryStatus(ordersSubmitDTO.getDeliveryStatus());
        orders.setDeliveryTime(ordersSubmitDTO.getEstimatedDeliveryTime());
        orders.setPackAmount(ordersSubmitDTO.getPackAmount());
        orders.setTablewareNumber(ordersSubmitDTO.getTablewareNumber());
        orders.setTablewareStatus(ordersSubmitDTO.getTablewareStatus());
        // 2.1 补充订单的冗余数据
        // 查询订单的地址信息（人、地址、手机号）
        AddressBook addressBook = addressBookMapper.getById(ordersSubmitDTO.getAddressBookId());
        orders.setUserName(addressBook.getConsignee());
        orders.setPhone(addressBook.getPhone());
        // 拼接地址 省 +市 + 区 +详情
        String address = addressBook.getProvinceName() + addressBook.getCityName() + addressBook.getDistrictName() + addressBook.getDetail();
        orders.setAddress(address);
        orders.setConsignee(addressBook.getConsignee());
        // TODO 这里要主键返回
        ordersMapper.insert(orders);

        // 3. 构建订单详情数据，主要就是买的什么东西
        // List<ShoppingCart> -->> List<OrderDetail>
        List<OrderDetail> orderDetails = shoppingCartList.stream()
                .map(item -> {
                    OrderDetail orderDetail = new OrderDetail();
                    BeanUtils.copyProperties(item, orderDetail);
                    orderDetail.setOrderId(orders.getId());
                    return orderDetail;
                }).collect(Collectors.toList());
        orderDetailMapper.insertBatch(orderDetails);
        // 4. 清空谁的购物车
        shoppingCartMapper.deleteByUserId(BaseContext.getCurrentId());
        // 5. 返回订单号、金额、 ID、时间
        OrderSubmitVO orderSubmitVO = new OrderSubmitVO();
        orderSubmitVO.setId(orders.getId());
        orderSubmitVO.setOrderNumber(orders.getNumber());
        orderSubmitVO.setOrderAmount(orders.getAmount());
        orderSubmitVO.setOrderTime(orders.getOrderTime());
        return orderSubmitVO;
    }

    @Override
    public void paySuccess(String number) {
        Orders orders = new Orders();
        orders.setNumber(number);
        orders.setStatus(Orders.TO_BE_CONFIRMED);
        orders.setCheckoutTime(LocalDateTime.now());
        orders.setPayStatus(1);
        ordersMapper.updateByNumber(orders);

        // 通过WebSocket发送约定的报文，来通知前端来新订单了
        Orders ordersByNumber = ordersMapper.selectByNumber(number);
        // type - orderId - content(订单号)
        JSONObject map = new JSONObject();
        map.put("type", 1);
        map.put("orderId", ordersByNumber.getId());
        map.put("content", number);
        webSocketServer.sendToAllClient(map.toJSONString());
    }

    @Override
    public PageResult historyOrders(OrdersPageQueryDTO ordersPageQueryDTO) {
        PageHelper.startPage(ordersPageQueryDTO.getPage(), ordersPageQueryDTO.getPageSize());
        Orders orders = new Orders();
        orders.setStatus(ordersPageQueryDTO.getStatus());
        orders.setUserId(BaseContext.getCurrentId());
        Page<Orders> page = ordersMapper.selectPage(orders);
        List<Orders> ordersList = page.getResult();

        List<OrderVO> orderVOS = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(ordersList)) {
            List<Long> orderIds = ordersList.stream().map(Orders::getId).collect(Collectors.toList());
            List<OrderDetail> orderDetailList = orderDetailMapper.selectListByOrderIds(orderIds);

            orderVOS = ordersList.stream().map(item -> {
                OrderVO orderVO = new OrderVO();
                BeanUtils.copyProperties(item, orderVO);
                List<OrderDetail> orderDetails = orderDetailList.stream()
                        .filter(orderDetail -> Objects.equals(orderDetail.getOrderId(), item.getId()))
                        .collect(Collectors.toList());
                orderVO.setOrderDetailList(orderDetails);
                return orderVO;
            }).collect(Collectors.toList());
        }
        return new PageResult(page.getTotal(), orderVOS);

    }

    @Override
    public OrderVO orderDetail(Long id) {
        return getOrderVO(id);
    }

    @Override
    public void cancelById(Long id) {
        Orders orders = new Orders();
        orders.setId(id);
        orders.setStatus(Orders.CANCELLED);
        orders.setPayStatus(2);
        orders.setCancelTime(LocalDateTime.now());
        ordersMapper.updateById(orders);
    }

    @Override
    public void repetition(Long id) {
        List<OrderDetail> orderDetailList = orderDetailMapper.selectListByOrderIds(Collections.singletonList(id));
        List<ShoppingCart> shoppingCarts = orderDetailList.stream()
                .map(orderDetail -> {
                    ShoppingCart shoppingCart = new ShoppingCart();
                    BeanUtils.copyProperties(orderDetail, shoppingCart);
                    shoppingCart.setUserId(BaseContext.getCurrentId());
                    shoppingCart.setCreateTime(LocalDateTime.now());
                    return shoppingCart;
                }).collect(Collectors.toList());
        shoppingCartMapper.insertBatch(shoppingCarts);
    }

    @Override
    public PageResult conditionSearch(OrdersPageQueryDTO ordersPageQueryDTO) {
        PageHelper.startPage(ordersPageQueryDTO.getPage(), ordersPageQueryDTO.getPageSize());
        Orders orders = new Orders();
        BeanUtils.copyProperties(ordersPageQueryDTO, orders);
        Page<Orders> page = ordersMapper.selectPage(orders);
        return new PageResult(page.getTotal(), page.getResult());
    }

    @Override
    public OrderStatisticsVO statistics() {
        return ordersMapper.selectStatistics();
    }

    @Override
    public OrderVO detailsById(Long id) {
        return getOrderVO(id);
    }

    @Override
    public void confirm(OrdersConfirmDTO ordersConfirmDTO) {
        Orders orders = new Orders();
        orders.setId(ordersConfirmDTO.getId());
        orders.setStatus(Orders.CONFIRMED);
        ordersMapper.updateById(orders);
    }

    @Override
    public void rejection(OrdersRejectionDTO ordersRejectionDTO) {
        Orders orders = new Orders();
        orders.setId(ordersRejectionDTO.getId());
        orders.setRejectionReason(ordersRejectionDTO.getRejectionReason());
        orders.setStatus(Orders.CONFIRMED);
        ordersMapper.updateById(orders);
    }

    @Override
    public void cancel(OrdersCancelDTO ordersCancelDTO) {
        Orders orders = new Orders();
        orders.setId(ordersCancelDTO.getId());
        orders.setCancelReason(ordersCancelDTO.getCancelReason());
        orders.setStatus(Orders.CANCELLED);
        ordersMapper.updateById(orders);
    }

    @Override
    public void deliveryById(Long id) {
        Orders orders = new Orders();
        orders.setId(id);
        orders.setStatus(Orders.DELIVERY_IN_PROGRESS);
        ordersMapper.updateById(orders);
    }

    @Override
    public void completeById(Long id) {
        Orders orders = new Orders();
        orders.setId(id);
        orders.setStatus(Orders.COMPLETED);
        ordersMapper.updateById(orders);
    }

    @Override
    public void reminder(Long id) {
        Orders orders = ordersMapper.selectById(id);
        // 1.订单得存在
        if (Objects.isNull(orders)) {
            throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
        }
        // 2.订单得在 待接单 的状态
        if (!Objects.equals(orders.getStatus(), Orders.TO_BE_CONFIRMED)) {
            throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
        }
        // json 约定
        JSONObject map = new JSONObject();
        // type=2 代表用户催单
        map.put("type", 2);
        map.put("orderId", id);
        map.put("content", "订单号：" + orders.getNumber());
        webSocketServer.sendToAllClient(map.toJSONString());
    }

    @Override
    public TurnoverReportVO turnoverStatistics(LocalDate begin, LocalDate end) {
        // 获取时间范围内，按天分组统计每天营业额之和
        // [{"order_time": "2020-10-10", "amount": 100}, {"order_time": "2020-10-10", "amount": 100}]
        List<Map<String, Object>> list = ordersMapper.selectTurnoverStatistics(begin, end);

        String dateList = list.stream()
                .map(map -> (String) map.get("format_order_time"))
                .collect(Collectors.joining(","));

        String turnoverList = list.stream()
                .map(map -> {
                    BigDecimal orderTime = (BigDecimal) map.get("sum_amount");
                    return orderTime.toString();
                })
                .collect(Collectors.joining(","));


        TurnoverReportVO turnoverReportVO = new TurnoverReportVO();
        // 营业额，以逗号分隔，例如：406.0,1520.0,75.0
        turnoverReportVO.setTurnoverList(turnoverList);
        // 日期，以逗号分隔，例如：2022-10-01,2022-10-02,2022-10-03
        turnoverReportVO.setDateList(dateList);
        return turnoverReportVO;
    }

    @Override
    public UserReportVO userStatistics(LocalDate begin, LocalDate end) {
        // 日期列表 按天分组 新增用户数
        List<Map<String, Object>> mapList = userMapper.selectUserStatistics(begin, end);

        // 获取时间的字符串 ['2020-01-01']
        List<String> dateList = mapList.stream()
                .map(item -> (String) item.get("format_create_time"))
                .collect(Collectors.toList());

        // 获取用户数的字符串
        String newUserList = mapList.stream()
                .map(item -> String.valueOf(item.get("count_user")))
                .collect(Collectors.joining(","));

        // 获取用户累计数 for List<String> --> List<String>
        // 2020-01-01 --> 数量 ->> String ->> 分割

        // ['2020-01-01', '2020-01-01', '2020-01-01', '2020-01-01']
        // [4, 5, 6, 7]
        // ['4', '5', '6', '7']
        // '4', '5', '6', '7'
        // 数据库优化
        String totalUserList = dateList.stream()
                .map(userMapper::selectCountByCreateTime)
                .map(Object::toString)
                .collect(Collectors.joining(","));

        // ArrayList<Integer> countList = new ArrayList<>();
        // dateList.forEach(date -> {
        //     Integer count = userMapper.selectCountByCreateTime(date);
        //     countList.add(count);
        // });
        // String totalUserList = countList.stream()
        //         .map(Object::toString)
        //         .collect(Collectors.joining(","));

        UserReportVO userReportVO = new UserReportVO();
        userReportVO.setDateList(String.join(",", dateList));
        userReportVO.setTotalUserList(totalUserList);
        userReportVO.setNewUserList(newUserList);

        return userReportVO;
    }

    @Override
    public OrderReportVO ordersStatistics(LocalDate begin, LocalDate end) {
        // 1.日期列表，以逗号分隔 - 按天分组，取每天的订单数
        List<Map<String, Object>> orderCountList = ordersMapper.selectOrderCountList(begin, end);

        List<String> orderTimeList = orderCountList.stream()
                .map(item -> (String) item.get("format_order_time"))
                .collect(Collectors.toList());

        // 会执行两次SQL，FRO 执行批量SQL 订单数 和有效订单数 和 日期 三个同时返回
        // 2.有效订单数列表，以逗号分隔 ['4-2', '4-3']
        List<Long> validOrderCountList = orderCountList.stream()
                .map(item -> (Long) item.get("valid_count"))
                .collect(Collectors.toList());

        // 3.订单数列表，以逗号分隔 按天分组，取每天的订单数 ['4-1', '4-2', '4-3']
        List<Long> ordersCountList = orderCountList.stream()
                .map(item -> (Long) item.get("orders_count"))
                .collect(Collectors.toList());

        // 4.订单总数
        long totalOrderCount = ordersCountList.stream().reduce(0L, Long::sum);

        // 5.有效订单数
        Long validOrderCount = validOrderCountList.stream().reduce(0L, Long::sum);

        // 6.订单完成率 = 有效订单数 / 全部订单数 -- Long - Integer ==> long
        Double orderCompletionRate = validOrderCount.doubleValue() / totalOrderCount;

        // 处理总订单数
        String ordersCountListStr = ordersCountList.stream()
                .map(Object::toString)
                .collect(Collectors.joining(","));

        // 处理有效订单数
        String validOrderCountListStr = validOrderCountList.stream()
                .map(Object::toString)
                .collect(Collectors.joining(","));

        OrderReportVO orderReportVO = new OrderReportVO();
        orderReportVO.setDateList(String.join(",", orderTimeList));
        orderReportVO.setOrderCountList(ordersCountListStr);
        orderReportVO.setValidOrderCountList(validOrderCountListStr);
        orderReportVO.setTotalOrderCount(Math.toIntExact(totalOrderCount));
        orderReportVO.setValidOrderCount(Math.toIntExact(validOrderCount));
        orderReportVO.setOrderCompletionRate(orderCompletionRate);

        return orderReportVO;
    }

    @Override
    public SalesTop10ReportVO top10(LocalDate begin, LocalDate end) {
        List<Map<String, Object>> top10Map = ordersMapper.selectTop10(begin, end);

        String nameList = top10Map.stream()
                .map(item -> {
                    return (String) item.get("name");
                }).collect(Collectors.joining(","));

        String numberList = top10Map.stream()
                .map(item -> {
                    return (Long) item.get("dish_count");
                })
                .map(item -> item.toString())
                .collect(Collectors.joining(","));

        SalesTop10ReportVO salesTop10ReportVO = new SalesTop10ReportVO();
        salesTop10ReportVO.setNameList(nameList);
        salesTop10ReportVO.setNumberList(numberList);

        return salesTop10ReportVO;

    }

    @Override
    public void export(HttpServletResponse response) {
        try {
            // 1. 读取Excel
            // 获取动态路径
            InputStream inp = this.getClass().getClassLoader().getResourceAsStream("excel.xlsx");
            Workbook wb = WorkbookFactory.create(inp);
            // 2. 修改Excel
            // 2.1 拿到sheet页
            Sheet sheetAt0 = wb.getSheetAt(0);
            // 生成时间
            LocalDate now = LocalDate.now();
            LocalDate begin = now.plusDays(-30);
            LocalDate end = now.plusDays(-1);
            String time = "生成时间:" + begin + "至" + end;

            Row row2 = sheetAt0.getRow(1);
            Cell cell22 = row2.getCell(1);

            cell22.setCellValue(time);
            // 营业额、订单完成率、新增用户数、有效订单、平均客单价
            BusinessDataVO businessDataVO = ordersMapper.selectBusinessDataVO(begin, end);

            Row row4 = sheetAt0.getRow(3);
            Row row5 = sheetAt0.getRow(4);
            Cell cell42 = row4.getCell(2);
            Cell cell44 = row4.getCell(4);
            Cell cell46 = row4.getCell(6);
            Cell cell52 = row5.getCell(2);
            Cell cell54 = row5.getCell(4);
            // 订单完成率进行百分比转换 0.16778 --> 16.78%
            BigDecimal bigDecimal = BigDecimal.valueOf(businessDataVO.getOrderCompletionRate())
                    .multiply(BigDecimal.valueOf(100))
                    .setScale(2, RoundingMode.HALF_UP);

            cell42.setCellValue("￥" + businessDataVO.getTurnover());
            cell44.setCellValue(bigDecimal + "%");
            cell46.setCellValue(businessDataVO.getNewUsers());
            cell52.setCellValue(businessDataVO.getValidOrderCount());
            cell54.setCellValue("￥" + businessDataVO.getUnitPrice());

            // 数据列表
            List<BusinessDataVO> businessDataVOList = ordersMapper.selectBusinessDataVOWithDay(begin, end);
            for (int i = 0; i < businessDataVOList.size(); i++) {
                BusinessDataVO dataVO = businessDataVOList.get(i);
                int rowIndex = i + 7;
                Row row = sheetAt0.getRow(rowIndex);

                BigDecimal orderCompletionRate = BigDecimal.valueOf(dataVO.getOrderCompletionRate())
                        .multiply(BigDecimal.valueOf(100))
                        .setScale(2, RoundingMode.HALF_UP);
                row.getCell(1).setCellValue(dataVO.getFormatOrderTime());
                row.getCell(2).setCellValue("￥" + dataVO.getTurnover());
                row.getCell(3).setCellValue(dataVO.getValidOrderCount());
                row.getCell(4).setCellValue(orderCompletionRate + "%");
                row.getCell(5).setCellValue("￥" + dataVO.getUnitPrice());
                row.getCell(6).setCellValue(dataVO.getNewUsers());
            }

            // 3. 要把Excel写进响应体
            ServletOutputStream outputStream = response.getOutputStream();
            wb.write(outputStream);

        } catch (Exception e) {
            log.error("表格导出失败：{}", e.getMessage());
        }
    }

    private OrderVO getOrderVO(Long id) {
        Orders orders = ordersMapper.selectById(id);
        List<OrderDetail> orderDetails = orderDetailMapper.selectListByOrderIds(Collections.singletonList(id));
        OrderVO orderVO = new OrderVO();
        BeanUtils.copyProperties(orders, orderVO);
        orderVO.setOrderDetailList(orderDetails);
        return orderVO;
    }
}
